/**
 * Copyright (c) 2018 软唐 All rights reserved.
 * <p>
 * https://www.softtown.cn
 * <p>
 * 版权所有，侵权必究！
 */

package com.softtown.modules.oss.cloud;


import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.utils.DateUtil;
import com.aliyun.oss.common.utils.HttpHeaders;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.ResponseHeaderOverrides;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.softtown.common.exception.ErrorCode;
import com.softtown.common.exception.RenException;
import com.softtown.modules.oss.entity.SysOssFileEntity;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static com.aliyun.oss.internal.OSSConstants.DEFAULT_OBJECT_CONTENT_TYPE;
import static com.aliyun.oss.internal.OSSHeaders.OSS_USER_METADATA_PREFIX;


/**
 * 阿里云存储
 *
 * @author Ding Ya Yong
 */
public class AliyunCloudStorageService extends AbstractCloudStorageService {

    public AliyunCloudStorageService(CloudStorageConfig config) {
        this.config = config;
    }

    @Override
    public String upload(byte[] data, String path) {
        return upload(new ByteArrayInputStream(data), path);
    }

    @Override
    public String upload(InputStream inputStream, String path) {
        String roleSessionName = "FirstOssToken";
        String policy = "{\n" +
                "    \"Version\": \"1\", \n" +
                "    \"Statement\": [\n" +
                "        {\n" +
                "            \"Action\": [\n" +
                "                \"oss:*\"\n" +
                "            ], \n" +
                "            \"Resource\": [\n" +
                "                \"acs:oss:*:*:*\" \n" +
                "            ], \n" +
                "            \"Effect\": \"Allow\"\n" +
                "        }\n" +
                "    ]\n" +
                "}";
        try {
            DefaultProfile.addEndpoint("", "", "Sts", "sts.aliyuncs.com");
            // 构造default profile（参数留空，无需添加region ID）
            IClientProfile profile = DefaultProfile.getProfile("", config.getAliyunAccessKeyId(), config.getAliyunAccessKeySecret());
            // 用profile构造client
            DefaultAcsClient clients = new DefaultAcsClient(profile);
            final AssumeRoleRequest request = new AssumeRoleRequest();
            request.setSysMethod(MethodType.POST);
            request.setRoleArn(config.getRoleArn());
            request.setRoleSessionName(roleSessionName);
            // 若policy为空，则用户将获得该角色下所有权限
            request.setPolicy(policy);
            // 设置凭证有效时间
            request.setDurationSeconds(3600L);
            final AssumeRoleResponse response = clients.getAcsResponse(request);
            OSS ossClient = new OSSClientBuilder().build(config.getAliyunEndPoint(), response.getCredentials().getAccessKeyId(), response.getCredentials().getAccessKeySecret(), response.getCredentials().getSecurityToken());
//            GeneratePresignedUrlRequest requests = new GeneratePresignedUrlRequest(config.getAliyunBucketName(),path.substring(config.getAliyunDomain().length()+1), HttpMethod.PUT);
//            // 设置URL过期时间为1小时。
//            Date expiration = new Date(System.currentTimeMillis()+ 3600L*1000*24);
//            requests.setExpiration(expiration);
//// 设置ContentType。
//            requests.setContentType(DEFAULT_OBJECT_CONTENT_TYPE);
//// 设置自定义元信息。
//            requests.addUserMetadata("author", "aliy");
//
//// 生成PUT方式的签名URL。
//            URL signedUrl = ossClient.generatePresignedUrl(requests);
//
//            Map<String, String> requestHeaders = new HashMap<String, String>();
//            requestHeaders.put(HttpHeaders.CONTENT_TYPE, DEFAULT_OBJECT_CONTENT_TYPE);
//            requestHeaders.put(OSS_USER_METADATA_PREFIX + "author", "aliy");
//            PutObjectRequest putObjectRequest = new
// 使用签名URL上传文件。
//            ossClient.putObject(signedUrl, new InputStream(path), -1, requestHeaders, true);

            ossClient.putObject(config.getAliyunBucketName(), path, inputStream);
            ossClient.shutdown();
        } catch (Exception e) {
            throw new RenException(ErrorCode.OSS_UPLOAD_FILE_ERROR, e, "");
        }

        return path;
    }

    @Override
    public String uploadSuffix(byte[] data, String suffix) {
        return upload(data, getPath(config.getAliyunPrefix(), suffix));
    }

    @Override
    public String uploadSuffix(InputStream inputStream, String suffix) {
        return upload(inputStream, getPath(config.getAliyunPrefix(), suffix));
    }

    @Override
    public String getHeadUrl(String path) {
        URL signedUrl = null;
        String roleSessionName = "FirstOssToken";
        String policy = "{\n" +
                "    \"Version\": \"1\", \n" +
                "    \"Statement\": [\n" +
                "        {\n" +
                "            \"Action\": [\n" +
                "                \"oss:*\"\n" +
                "            ], \n" +
                "            \"Resource\": [\n" +
                "                \"acs:oss:*:*:*\" \n" +
                "            ], \n" +
                "            \"Effect\": \"Allow\"\n" +
                "        }\n" +
                "    ]\n" +
                "}";
        try {
            DefaultProfile.addEndpoint("", "", "Sts", "sts.aliyuncs.com");
            // 构造default profile（参数留空，无需添加region ID）
            IClientProfile profile = DefaultProfile.getProfile("", config.getAliyunAccessKeyId(), config.getAliyunAccessKeySecret());
            // 用profile构造client
            DefaultAcsClient clients = new DefaultAcsClient(profile);
            final AssumeRoleRequest request = new AssumeRoleRequest();
            request.setSysMethod(MethodType.POST);
            request.setRoleArn(config.getRoleArn());
            request.setRoleSessionName(roleSessionName);
            // 若policy为空，则用户将获得该角色下所有权限
            request.setPolicy(policy);
            // 设置凭证有效时间
            request.setDurationSeconds(3600L);
            final AssumeRoleResponse response = clients.getAcsResponse(request);
            OSS ossClient = new OSSClientBuilder().build(config.getAliyunEndPoint(), response.getCredentials().getAccessKeyId(), response.getCredentials().getAccessKeySecret(), response.getCredentials().getSecurityToken());
            GeneratePresignedUrlRequest requests = new GeneratePresignedUrlRequest(config.getAliyunBucketName(), path, HttpMethod.GET);
            Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24);
            requests.setExpiration(expiration);
//设置响应头强制下载
            ResponseHeaderOverrides responseHeaders = new ResponseHeaderOverrides();
            responseHeaders.setContentDisposition("attachment;");
            requests.setResponseHeaders(responseHeaders);
            signedUrl = ossClient.generatePresignedUrl(requests);

            // URL签名方式。
//            OSS ossClient = new OSSClientBuilder().build(config.getAliyunEndPoint(), config.getAliyunAccessKeyId(), config.getAliyunAccessKeySecret());
//            GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(config.getAliyunBucketName(), path.substring(config.getAliyunDomain().length()+1), HttpMethod.GET);
//            // 设置URL过期时间。
//            Date expiration = new Date(System.currentTimeMillis()+ 3600L*1000*24);
//            request.setExpiration(expiration);
//            signedUrl = ossClient .generatePresignedUrl(request);
            // 关闭OSSClient。
            ossClient.shutdown();
        } catch (Exception e) {
            throw new RenException(ErrorCode.OSS_UPLOAD_FILE_ERROR, e, "");
        }
        return String.valueOf(signedUrl);
    }

    @Override
    public void deleteFile(String path) {

        String roleSessionName = "FirstOssToken";
        String policy = "{\n" +
                "    \"Version\": \"1\", \n" +
                "    \"Statement\": [\n" +
                "        {\n" +
                "            \"Action\": [\n" +
                "                \"oss:*\"\n" +
                "            ], \n" +
                "            \"Resource\": [\n" +
                "                \"acs:oss:*:*:*\" \n" +
                "            ], \n" +
                "            \"Effect\": \"Allow\"\n" +
                "        }\n" +
                "    ]\n" +
                "}";
        try {
            DefaultProfile.addEndpoint("", "", "Sts", "sts.aliyuncs.com");
            // 构造default profile（参数留空，无需添加region ID）
            IClientProfile profile = DefaultProfile.getProfile("", config.getAliyunAccessKeyId(), config.getAliyunAccessKeySecret());
            // 用profile构造client
            DefaultAcsClient clients = new DefaultAcsClient(profile);
            final AssumeRoleRequest request = new AssumeRoleRequest();
            request.setSysMethod(MethodType.POST);
            request.setRoleArn(config.getRoleArn());
            request.setRoleSessionName(roleSessionName);
            // 若policy为空，则用户将获得该角色下所有权限
            request.setPolicy(policy);
            // 设置凭证有效时间
            request.setDurationSeconds(3600L);
            final AssumeRoleResponse response = clients.getAcsResponse(request);
            OSS ossClient = new OSSClientBuilder().build(config.getAliyunEndPoint(), response.getCredentials().getAccessKeyId(), response.getCredentials().getAccessKeySecret(), response.getCredentials().getSecurityToken());
            ossClient.deleteObject(config.getAliyunBucketName(), path);
        } catch (Exception e) {
            throw new RenException(ErrorCode.OSS_UPLOAD_FILE_ERROR, e, "");
        }
    }

    @Override
    public SysOssFileEntity getStsToken(String path) {
        SysOssFileEntity sysOssFileEntity = new SysOssFileEntity();
        URL signedUrl = null;
        String roleSessionName = "FirstOssToken";
        String region = "oss-cn-shanghai";
        String policy = "{\n" +
                "    \"Version\": \"1\", \n" +
                "    \"Statement\": [\n" +
                "        {\n" +
                "            \"Action\": [\n" +
                "                \"oss:*\"\n" +
                "            ], \n" +
                "            \"Resource\": [\n" +
                "                \"acs:oss:*:*:*\" \n" +
                "            ], \n" +
                "            \"Effect\": \"Allow\"\n" +
                "        }\n" +
                "    ]\n" +
                "}";
        try {
            DefaultProfile.addEndpoint("", "", "Sts", "sts.aliyuncs.com");
            // 构造default profile（参数留空，无需添加region ID）
            IClientProfile profile = DefaultProfile.getProfile("", config.getAliyunAccessKeyId(), config.getAliyunAccessKeySecret());
            // 用profile构造client
            DefaultAcsClient clients = new DefaultAcsClient(profile);
            final AssumeRoleRequest request = new AssumeRoleRequest();
            request.setSysMethod(MethodType.POST);
            request.setRoleArn(config.getRoleArn());
            request.setRoleSessionName(roleSessionName);
            // 若policy为空，则用户将获得该角色下所有权限
            request.setPolicy(policy);
            // 设置凭证有效时间
            request.setDurationSeconds(3600L);
            final AssumeRoleResponse response = clients.getAcsResponse(request);
            OSS ossClient = new OSSClientBuilder().build(config.getAliyunEndPoint(), response.getCredentials().getAccessKeyId(), response.getCredentials().getAccessKeySecret(), response.getCredentials().getSecurityToken());
            GeneratePresignedUrlRequest requests = new GeneratePresignedUrlRequest(config.getAliyunBucketName(), path, HttpMethod.GET);
            Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24);
            requests.setExpiration(expiration);

            signedUrl = ossClient.generatePresignedUrl(requests);
            ossClient.shutdown();
            sysOssFileEntity.setAccessKeyId(response.getCredentials().getAccessKeyId());
            sysOssFileEntity.setAccessKeySecret(response.getCredentials().getAccessKeySecret());
            sysOssFileEntity.setBucket(config.getAliyunBucketName());
            sysOssFileEntity.setRegion(region);
            sysOssFileEntity.setStsToken(URLEncoder.encode(response.getCredentials().getSecurityToken(), "utf-8"));
            sysOssFileEntity.setUrl(String.valueOf(signedUrl));
        } catch (ClientException e) {
            e.printStackTrace();
            System.out.println("Failed：");
            System.out.println("Error code: " + e.getErrCode());
            System.out.println("Error message: " + e.getErrMsg());
            System.out.println("RequestId: " + e.getRequestId());
        } catch (UnsupportedEncodingException u) {
            u.printStackTrace();
        }
        return sysOssFileEntity;
    }
}